﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// This is a gaussian skin detector
    /// </summary>
    public class GaussianSkin : BaseForeBackgroundColorFilter
    {
        protected Color m_DispSample;
        protected Color m_MeanSample;
        protected Bitmap sampleImage;
        protected double m_dThreshold = 0.5;

        /// <summary>
        /// Initializes a new instance of the <see cref="GaussianSkin"/> class.
        /// </summary>
        public GaussianSkin()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GaussianSkin"/> class.
        /// </summary>
        /// <param name="_gaussianSkin">The _gaussian skin.</param>
        internal GaussianSkin(GaussianSkin _gaussianSkin)
        {
            this.m_dThreshold = _gaussianSkin.m_dThreshold;
        }

        /// <summary>
        /// Gets or sets the threshold
        /// </summary>
        public double Threshold
        {
            get { return m_dThreshold; }
            set { m_dThreshold = value; }
        }

        /// <summary>
        /// Skin Filter
        /// </summary>
        /// <param name="_bitmap"></param>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            this.m_MeanSample = ColorFunctions.GetMeanValue(_bitmap);
            this.m_DispSample = ColorFunctions.GetDispersion(_bitmap);

            Color colorToSet = Color.Transparent;

            UnsafeBitmap bitmap = _bitmap;

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            for (int y = 0; y < nHeight; y++)
            {
                for (int x = 0; x < nWidth; x++)
                {
                    Color color = _bitmap.GetPixel(x, y);
                    if (IsSkin(color))
                    {
                        colorToSet = color;
                    }
                    else
                    {
                        colorToSet = m_ColorBackground;
                    }
                    _bitmap.SetPixel(x, y, colorToSet);
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// This should determine if skin color is found
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        private bool IsSkin(Color color)
        {
            int nDispR = m_DispSample.R;
            int nDispG = m_DispSample.G;
            int nDispB = m_DispSample.B;
            double pR = (1.0 / ((6.2831853071795862 * nDispR) / 255.0)) * Math.Exp(((-0.5 * (color.R - nDispR)) * (color.R - nDispR)) / 65536.0);
            double pG = (1.0 / ((6.2831853071795862 * nDispG) / 255.0)) * Math.Exp(((-0.5 * (color.G - nDispG)) * (color.G - nDispG)) / 65536.0);
            double pB = (1.0 / ((6.2831853071795862 * nDispB) / 255.0)) * Math.Exp(((-0.5 * (color.B - nDispB)) * (color.B - nDispB)) / 65536.0);
            return (((pR + pG) + pB) < this.m_dThreshold);
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new GaussianSkin(this);
        }
    }
}
